package com.code2roc.fastboot.system.setting.bizlogic;

import com.code2roc.fastboot.model.UserTokenModel;
import com.code2roc.fastboot.system.enums.CommonEnum;
import com.code2roc.fastboot.system.enums.MenuEnum;
import com.code2roc.fastboot.system.org.model.SystemRoleDO;
import com.code2roc.fastboot.system.setting.model.SystemMenuDO;
import com.code2roc.fastboot.system.setting.model.SystemMenuSettingDO;
import com.code2roc.fastboot.system.setting.service.ISystemMenuService;
import com.code2roc.fastboot.system.setting.service.ISystemMenuSettingService;
import com.code2roc.fastboot.model.BaseBootLogic;
import com.code2roc.fastboot.util.BootUtil;
import com.code2roc.fastboot.framework.util.CopyUtil;
import com.code2roc.fastboot.framework.database.CommonDTO;
import com.code2roc.fastboot.framework.util.*;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class MenuLogic extends BaseBootLogic {
    @Autowired
    private ISystemMenuService service;
    @Autowired
    private ISystemMenuSettingService settingService;
    @Autowired
    private CommonDTO commonDTO;

    public void insert(SystemMenuDO entity){
        if(StringUtil.isEmpty(entity.getMenu_code())){
            entity.setMenu_code(createMenuCode(entity.getParent_menu_code()));
        }
        service.insert(entity);
    }

    public void delete(String row_id){
        SystemMenuDO entity = service.selectOne(row_id);
        List<SystemMenuDO> subMenuList = service.selectSubMenuByMenuCode(entity.getMenu_code());
        List<String> rowIDList = new ArrayList<String>();
        for (SystemMenuDO item : subMenuList) {
            rowIDList.add(item.getRow_id());
        }
        service.batchDelte(rowIDList);
    }

    public void update(SystemMenuDO entity){
        SystemMenuDO old = detail(entity.getRow_id());
        if (old.getParent_menu_code().equals(entity.getParent_menu_code())) {
            service.update(entity);
        } else {
            String newMenuCode = createMenuCode(entity.getParent_menu_code());
            entity.setMenu_code(newMenuCode);
            //更新子集菜单的menucode
            HashMap paramMap = new HashMap();
            paramMap.put("newMenuCode", newMenuCode);
            paramMap.put("oldMenuCodeLength", old.getMenu_code().length() + 1);
            paramMap.put("oldMenuCodeLike", old.getMenu_code() + "%");
            paramMap.put("oldMenuCode", old.getMenu_code());
            String sql = "update system_menu set menu_code = CONCAT(#{newMenuCode},SUBSTRING(menu_code, #{oldMenuCodeLength})) where menu_code like #{oldMenuCodeLike} and menu_code!= #{oldMenuCode}";
            commonDTO.executeSQL(sql, paramMap);
            service.update(entity);
        }
    }

    public SystemMenuDO detail(String row_id){
        SystemMenuDO entity = service.selectOne(row_id);
        entity.setParent_menu_code(entity.getMenu_code().substring(0, entity.getMenu_code().length() - 4));
        return entity;
    }

    public void changeStatus(String row_id){
        SystemMenuDO entity = service.selectOne(row_id);
        if(entity.getMenu_status()== CommonEnum.EnableOrDisable.Enable.get_value()){
            entity.setMenu_status(CommonEnum.EnableOrDisable.Disable.get_value());
        }else{
            entity.setMenu_status(CommonEnum.EnableOrDisable.Enable.get_value());
        }
        service.update(entity);
    }

    public List<SystemRoleDO> getMenuRoleList(String menu_id, List<SystemRoleDO> roleDOList, List<SystemMenuSettingDO> menuSettingDOList) {
        SystemMenuDO menuDO = service.selectOne(menu_id);
        List<SystemMenuSettingDO> settingDOList = menuSettingDOList.stream().filter((SystemMenuSettingDO f) -> f.getMenu_id().equals(menu_id)).collect(Collectors.toList());
        List<SystemRoleDO> allRoleListCopy = CopyUtil.deepCopyList(roleDOList);
        for (SystemRoleDO roleDO : allRoleListCopy) {
            List<SystemMenuSettingDO> realitonfilter = settingDOList.stream().filter((SystemMenuSettingDO f) -> f.getSetting_id().equals(roleDO.getRow_id())).collect(Collectors.toList());
            if (realitonfilter.size() > 0) {
                roleDO.setRegist(true);
            } else {
                roleDO.setRegist(false);
            }
        }
        SystemRoleDO publicRole = new SystemRoleDO();
        publicRole.setRole_name("完全公开");
        publicRole.setRow_id("PublicRole");
        publicRole.setRegist(menuDO.getPublic_status()== MenuEnum.PublicStatus.Public.get_value());
        allRoleListCopy.add(0,publicRole);
        return allRoleListCopy;
    }

    public void updateRoleSetting(String menu_id,String role_id,boolean regist){
        if(!role_id.equals("PublicRole")){
            settingService.deleteSetting(menu_id,role_id);
            if(regist){
                SystemMenuSettingDO menuSettingDO = new SystemMenuSettingDO();
                menuSettingDO.setMenu_id(menu_id);
                menuSettingDO.setSetting_id(role_id);
                menuSettingDO.setSetting_mode(MenuEnum.SettingModel.RoleSetting.get_value());
                settingService.insert(menuSettingDO);
            }
        }else{
            SystemMenuDO menuDO = service.selectOne(menu_id);
            if(regist){
                menuDO.setPublic_status(MenuEnum.PublicStatus.Public.get_value());
            }else{
                menuDO.setPublic_status(MenuEnum.PublicStatus.NoPublic.get_value());
            }
            service.update(menuDO);
        }

    }

    public void updateMenuSetting(String menu_id,List<String> deptSettingList,List<String> userSettingList,List<String> roleSettingList){
        SystemMenuDO menuDO = service.selectOne(menu_id);
        menuDO.setPublic_status(MenuEnum.PublicStatus.NoPublic.get_value());
        settingService.deleteSetting(menu_id);
        for (String setting_id:deptSettingList) {
            SystemMenuSettingDO menuSettingDO = new SystemMenuSettingDO();
            menuSettingDO.setMenu_id(menu_id);
            menuSettingDO.setSetting_id(setting_id);
            menuSettingDO.setSetting_mode(MenuEnum.SettingModel.DeptSetting.get_value());
            settingService.insert(menuSettingDO);
        }
        for (String setting_id:userSettingList) {
            SystemMenuSettingDO menuSettingDO = new SystemMenuSettingDO();
            menuSettingDO.setMenu_id(menu_id);
            menuSettingDO.setSetting_id(setting_id);
            menuSettingDO.setSetting_mode(MenuEnum.SettingModel.UserSetting.get_value());
            settingService.insert(menuSettingDO);
        }
        for (String setting_id:roleSettingList) {
            if(!setting_id.equals("PublicRole")){
                SystemMenuSettingDO menuSettingDO = new SystemMenuSettingDO();
                menuSettingDO.setMenu_id(menu_id);
                menuSettingDO.setSetting_id(setting_id);
                menuSettingDO.setSetting_mode(MenuEnum.SettingModel.RoleSetting.get_value());
                settingService.insert(menuSettingDO);
            }else{
                menuDO.setPublic_status(MenuEnum.PublicStatus.Public.get_value());
            }
        }
        service.update(menuDO);
    }

    public List<SystemMenuDO> getUserMenuList(){
        List<SystemMenuDO> showMenuList = new ArrayList<>();
        List<SystemMenuDO> menuDOList = service.selectAllList().stream().filter(a->a.getMenu_status()== CommonEnum.EnableOrDisable.Enable.get_value()).collect(Collectors.toList());
        List<SystemMenuSettingDO> settingDOList = settingService.selectAllList();
        List<SystemMenuSettingDO> settingDOFilterList = new ArrayList<>();
        UserTokenModel userTokenModel = authUtil.getUserTokenModel();
        for (SystemMenuDO menu:menuDOList) {
            boolean show = false;
            if(menu.getMenu_code().startsWith("0099")){
                if(userTokenModel.getRoleName().contains("系统管理员")){
                    show = true;
                }else{
                    settingDOFilterList = settingDOList.stream().filter(a->a.getMenu_id().equals(menu.getRow_id())).collect(Collectors.toList());
                    if(settingDOFilterList.size()>0){
                        long count = settingDOFilterList.stream().filter(a->a.getSetting_mode()== MenuEnum.SettingModel.RoleSetting.get_value() && userTokenModel.getRoleID().contains(a.getSetting_id())).count();
                        if(count>0){
                            show = true;
                        }
                        count = settingDOFilterList.stream().filter(a->a.getSetting_mode()== MenuEnum.SettingModel.UserSetting.get_value() && userTokenModel.getUserID().contains(a.getSetting_id())).count();
                        if(count>0){
                            show = true;
                        }
                        count = settingDOFilterList.stream().filter(a->a.getSetting_mode()== MenuEnum.SettingModel.DeptSetting.get_value() && userTokenModel.getDeptID().contains(a.getSetting_id())).count();
                        if(count>0){
                            show = true;
                        }
                    }
                }
            }else{
                settingDOFilterList = settingDOList.stream().filter(a->a.getMenu_id().equals(menu.getRow_id())).collect(Collectors.toList());
                if(settingDOFilterList.size()>0){
                    long count = settingDOFilterList.stream().filter(a->a.getSetting_mode()== MenuEnum.SettingModel.RoleSetting.get_value() && userTokenModel.getRoleID().contains(a.getSetting_id())).count();
                    if(count>0){
                        show = true;
                    }
                    count = settingDOFilterList.stream().filter(a->a.getSetting_mode()== MenuEnum.SettingModel.UserSetting.get_value() && userTokenModel.getUserID().contains(a.getSetting_id())).count();
                    if(count>0){
                        show = true;
                    }
                    count = settingDOFilterList.stream().filter(a->a.getSetting_mode()== MenuEnum.SettingModel.DeptSetting.get_value() && userTokenModel.getDeptID().contains(a.getSetting_id())).count();
                    if(count>0){
                        show = true;
                    }
                }
            }
            if(show || menu.getPublic_status()== MenuEnum.PublicStatus.Public.get_value()){
                showMenuList.add(menu);
            }
        }

        //检查返回的子级是否包含上级，如果不包含，需要再补充
        List<String> extraMenuList = new ArrayList<String>();
        String menuCode = "";
        for (SystemMenuDO menu : showMenuList) {
            menuCode = menu.getMenu_code();
            menuCode = menuCode.substring(0, menuCode.length() - 4);
            while (menuCode.length() > 0) {
                boolean isexist = false;
                for (SystemMenuDO f : showMenuList) {
                    if (f.getMenu_code().equals(menuCode)) {
                        isexist = true;
                        break;
                    }
                }
                if (!isexist && !extraMenuList.contains(menuCode)) {
                    extraMenuList.add(menuCode);
                }
                menuCode = menuCode.substring(0, menuCode.length() - 4);
            }
        }
        //合并检查缺失的父级菜单
        if (extraMenuList.size() > 0) {
            showMenuList.addAll(menuDOList.stream().filter((SystemMenuDO menu) -> extraMenuList.contains(menu.getMenu_code())).collect(Collectors.toList()));
        }
        return showMenuList;
    }

    private String createMenuCode(String parentMenuCode) {
        String sql = "select menu_code from system_menu where length(menu_code) =" + (parentMenuCode.length() + 4) + " and left(menu_code," + parentMenuCode.length() + ")='" + parentMenuCode + "'" + "  order by menu_code desc LIMIT 1";
        String menucode = ConvertOp.convert2String(commonDTO.executeSQLToQuery(sql,null));
        if (StringUtil.isEmpty(menucode)) {
            return parentMenuCode + "0001";
        } else {
            return parentMenuCode + StringUtil.padLeft(String.valueOf(Integer.parseInt(menucode.substring(menucode.length() - 4)) + 1), 4, '0');
        }
    }

    public String exportData() {
        String fileid = "";
        try {
            DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
            Calendar calendar = Calendar.getInstance();
            String dateName = df.format(calendar.getTime());
            fileid = "MenuExport_" + dateName + CommonUtil.getNewGuid();
            String filename = fileid + ".xml";
            String filefullpath = "tempfiles/export/" + filename;
            FileUtil.initfloderPath("tempfiles/export/");
            Document doc = DocumentHelper.createDocument();
            Element root = doc.addElement("settingfile");
            Element filetype = root.addElement("filetype");
            filetype.setText("menu");

            Element menulist = root.addElement("menulist");
            List<SystemMenuDO> menuDOList = service.selectAllList();
            for (SystemMenuDO menuDO : menuDOList) {
                Element menu = menulist.addElement("menu");
                for (Field field : menuDO.getClass().getDeclaredFields()) {
                    if (!Modifier.isStatic(field.getModifiers())) {
                        field.setAccessible(true);
                        Element tablefield = menu.addElement(field.getName());
                        tablefield.setText(String.valueOf(field.get(menuDO)));
                    }
                }
            }

            Element menusettinglist = root.addElement("menusettinglist");
            List<SystemMenuSettingDO> menuSettingDOList = settingService.selectAllList();
            for (SystemMenuSettingDO settingDO : menuSettingDOList) {
                Element menusetting = menusettinglist.addElement("menusetting");
                for (Field field : settingDO.getClass().getDeclaredFields()) {
                    if (!Modifier.isStatic(field.getModifiers())) {
                        field.setAccessible(true);
                        Element tablefield = menusetting.addElement(field.getName());
                        tablefield.setText(String.valueOf(field.get(settingDO)));
                    }
                }
            }

            OutputFormat format = OutputFormat.createPrettyPrint();
            format.setEncoding("utf-8");
            FileOutputStream out;
            out = new FileOutputStream(filefullpath);
            XMLWriter writer = new XMLWriter(out, format);
            writer.write(doc);
            writer.close();

            StringBuilder builder = new StringBuilder();
            builder.append("导出菜单信息成功！" + CommonUtil.getNewLine());
            LogUtil.writeLog("setting/menu", "log", builder.toString());
        } catch (Exception e) {
            e.printStackTrace();
            StringBuilder builder = new StringBuilder();
            builder.append("导出菜单信息失败！" + CommonUtil.getNewLine());
            builder.append("失败异常信息:" + CommonUtil.getNewLine());
            builder.append(e.getMessage() + CommonUtil.getNewLine());
            builder.append("失败堆栈信息:" + CommonUtil.getNewLine());
            builder.append(e.getStackTrace());
            LogUtil.writeLog("setting/menu", "log", builder.toString());
        }
        return fileid;
    }

    @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.READ_UNCOMMITTED)
    public String importData(InputStream stream) {
        String errormsg = "";
        Exception exception = null;
        try {
            //解析xml
            SAXReader reader = new SAXReader();
            Document document = reader.read(stream);
            Element root = document.getRootElement();
            Element filetype = root.element("filetype");
            if (filetype != null && filetype.getText().equals("menu")) {

                List<Element> menulist = root.element("menulist").elements("menu");
                service.deleteAll();;
                for (Element menu : menulist) {
                    SystemMenuDO menuDO = new SystemMenuDO();
                    for (Field field : menuDO.getClass().getDeclaredFields()) {
                        if (!Modifier.isStatic(field.getModifiers())) {
                            field.setAccessible(true);
                            Element filednode = menu.element(field.getName());
                            field.set(menuDO, BootUtil.convetXmlContent2FieldContent(filednode.getText(), field.getType()));
                        }
                    }
                    insert(menuDO);
                }

                List<Element> menusettinglist = root.element("menusettinglist").elements("menusetting");
                settingService.deleteAll();
                for (Element menusetting : menusettinglist) {
                    SystemMenuSettingDO settingDO = new SystemMenuSettingDO();
                    for (Field field : settingDO.getClass().getDeclaredFields()) {
                        if (!Modifier.isStatic(field.getModifiers())) {
                            field.setAccessible(true);
                            Element filednode = menusetting.element(field.getName());
                            field.set(settingDO, BootUtil.convetXmlContent2FieldContent(filednode.getText(), field.getType()));
                        }
                    }
                    settingService.insert(settingDO);
                }
            } else {
                errormsg = "导入文件不是菜单文件！";
            }
        } catch (Exception e) {
            exception = e;
            errormsg = "导入失败";
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            e.printStackTrace();
        } finally {
            StringBuilder builder = new StringBuilder();
            if (StringUtil.isEmpty(errormsg)) {
                builder.append("导入菜单成功！" + CommonUtil.getNewLine());
            } else {
                builder.append("导入菜单失败！" + CommonUtil.getNewLine());
            }
            if (!StringUtil.isEmpty(errormsg)) {
                if (errormsg.equals("导入失败")) {
                    builder.append("失败异常信息:" + CommonUtil.getNewLine());
                    builder.append(exception.getMessage() + CommonUtil.getNewLine());
                    builder.append("失败堆栈信息:" + CommonUtil.getNewLine());
                    builder.append(exception.getStackTrace());
                } else {
                    builder.append("导入失败信息:" + errormsg + CommonUtil.getNewLine());
                }
            }
            LogUtil.writeLog("setting/menu", "log", builder.toString());
        }
        return errormsg;
    }
}
